
#include "Universe.hpp"
#include "ValueNode.hpp"

ValueNode::ValueNode() :
        ExpressionNode(),
        _name(-1)
{

}

ValueNode::ValueNode(char name) :
        ExpressionNode(),
        _name(name)
{

}

ValueNode::~ValueNode()
{

}

Tribool ValueNode::solve(Universe& universe)
{
    if (this->_solved)
        return this->_value;
    if (universe.isFact(this->_name))
        this->_value = universe.getFact(this->_name);
    else if (!this->_childs.empty())
    {
        std::list<ExpressionNode*>::const_iterator ite = this->_childs.end();
        for (std::list<ExpressionNode*>::const_iterator it = this->_childs.begin(); it != ite; it++)
        {
            Tribool r = (*it)->solve(universe);
            if (r.value != TriboolVal::Undefined)
            {
                this->_value = r;
                break;
            }
        }
    }
    else
        this->_value = this->_askHuman();
    // universe.addFact(this->_name, this->_value);
    this->_solved = true;
    return this->_value;
}

ExpressionNode* ValueNode::clone(std::map<int, ExpressionNode*>& existingNodes)
{
    if (existingNodes.find(this->_id) != existingNodes.end())
        return existingNodes[this->_id];
    ValueNode* clone = new ValueNode(this->_name);
    clone->_id = this->_id;
    clone->_solved = this->_solved;
    clone->_value = this->_value;
    existingNodes[this->_id] = clone;
    std::list<ExpressionNode*>::iterator ite = this->_childs.end();
    for (std::list<ExpressionNode*>::iterator it = this->_childs.begin(); it != ite; it++)
        clone->addChild((*it)->clone(existingNodes));
    return clone;
}

Tribool ValueNode::_askHuman() const
{
    char c = 0;
    do
    {
        std::cout << "Couldn't find " << this->_name << " value. Could you give one ? True (t), False (f) or Undefined (u) ? ";
        std::cin >> c;
    } while (c != 't' && c != 'f' && c != 'u');
    switch (c)
    {
    case 't':
        return Tribool(TriboolVal::True);
        break;
    case 'f':
        return Tribool(TriboolVal::False);
        break;
    }
    return Tribool(TriboolVal::Undefined);
}

void ValueNode::addChild(ExpressionNode* child)
{
    this->_childs.push_back(child);
}

NodeType::Type ValueNode::getType() const
{
    return NodeType::Value;
}

char ValueNode::getName() const
{
    return this->_name;
}
